public class Sort {
    public static void main(String[] args) {
    }
}

class InsertionSort {
    public static void insertionSort(int[] array) {
        int n = array.length;
        for (int i = 1; i < n; i++) {
            int key = array[i];
            int j = i - 1;
            // 将比 key 大的元素向右移动
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j--;
            }
            // 插入 key 到合适的位置
            array[j + 1] = key;
        }
    }
}

class ShellSort {
    public static void shellSort(int[] array) {
        int n = array.length;
        // 初始步长为数组长度的一半
        for (int gap = n / 2; gap > 0; gap /= 2) {
            // 进行插入排序，步长为gap
            // 多组集合 “一起” 排序
            for (int i = gap; i < n; i++) {
                int temp = array[i];
                int j = i;
                // 将array[j-gap], array[j-2*gap], ...依次与array[j]比较并移动
                while (j >= gap && array[j - gap] > temp) {
                    array[j] = array[j - gap];
                    j -= gap;
                }
                array[j] = temp;
            }
        }
    }
}

class SelectionSort {
    public static void selectionSort(int[] arr) {
        int n = arr.length;
        // 选择排序的核心算法
        for (int i = 0; i < n - 1; i++) {
            // 找到未排序部分的最小元素的索引
            int minIndex = i;
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            // 将未排序部分的最小元素与当前位置的元素交换
            int temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}

class HeapSort {
    public static void heapSort(int[] array) {
        int n = array.length;
        // 构建最大堆
        for (int i = n / 2 - 1; i >= 0; i--) {
            heapify(array, n, i);
        }
        // 从堆顶开始逐个取出元素，再调整堆结构
        for (int i = n - 1; i >= 0; i--) {
            // 将堆顶元素（最大值）与当前未排序部分的最后一个元素交换
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            // 调整堆结构，使剩余部分仍然是一个最大堆
            heapify(array, i, 0);
        }
    }
    // 对以某个节点为根的子树进行堆调整，确保以该节点为根的子树满足最大堆性质
    public static void heapify(int[] array, int n, int i) {
        int largest = i; // 假设当前节点是最大的
        int leftChild = 2 * i + 1; // 左孩子节点的索引
        int rightChild = 2 * i + 2; // 右孩子节点的索引
        // 如果左孩子节点比当前节点大，则更新最大值索引
        if (leftChild < n && array[leftChild] > array[largest]) {
            largest = leftChild;
        }
        // 如果右孩子节点比当前节点大，则更新最大值索引
        if (rightChild < n && array[rightChild] > array[largest]) {
            largest = rightChild;
        }
        // 如果最大值不是当前节点，需要交换节点，并递归调整子树
        if (largest != i) {
            int temp = array[i];
            array[i] = array[largest];
            array[largest] = temp;
            // 递归调整子树
            heapify(array, n, largest);
        }
    }
}

class BubbleSort {
    // 冒泡排序函数
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换arr[j]和arr[j+1]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            // 找到分区点并进行分区
            int pivotIndex = partition(arr, low, high);
            // 递归地对分区点左边的子数组进行快速排序
            quickSort(arr, low, pivotIndex - 1);
            // 递归地对分区点右边的子数组进行快速排序
            quickSort(arr, pivotIndex + 1, high);
        }
    }
    public static int partition(int[] arr, int low, int high) {
        // 选择第一个元素作为基准元素
        int pivot = arr[low];
        int left = low + 1;
        int right = high;
        while (true) {
            // 从左边找到第一个大于基准元素的元素
            while (left <= right && arr[left] <= pivot) {
                left++;
            }
            // 从右边找到第一个小于基准元素的元素
            while (left <= right && arr[right] >= pivot) {
                right--;
            }
            // 如果左右指针相遇，则结束循环
            if (left > right) {
                break;
            }
            // 交换左右指针所指向的元素
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }
        // 将基准元素放置到正确的位置
        int temp = arr[low];
        arr[low] = arr[right];
        arr[right] = temp;
        // 返回分区点位置
        return right;
    }
}

class MergeSort {
    // 合并两个有序数组
    private static void merge(int[] arr, int left, int mid, int right) {
        int n1 = mid - left + 1;
        int n2 = right - mid;
        int[] L = new int[n1];
        int[] R = new int[n2];
        // 将数据复制到临时数组
        for (int i = 0; i < n1; ++i)
            L[i] = arr[left + i];
        for (int j = 0; j < n2; ++j)
            R[j] = arr[mid + 1 + j];
        // 合并两个临时数组
        int i = 0, j = 0;
        int k = left;
        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                arr[k] = L[i];
                i++;
            } else {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
        // 复制剩余元素（如果有的话）
        while (i < n1) {
            arr[k] = L[i];
            i++;
            k++;
        }
        while (j < n2) {
            arr[k] = R[j];
            j++;
            k++;
        }
    }
    // 归并排序主方法
    private static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int mid = (left + right) / 2;
            // 递归排序左右两部分
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            // 合并已排序的子数组
            merge(arr, left, mid, right);
        }
    }
}

